// 版权归Go作者所有。版权所有。
// 此源代码的使用受BSD样式的约束
// 可以在许可证文件中找到的许可证。

// 包导入器提供对导出数据导入器的访问。
package importer

import (
	"go/build"
	"go/internal/gccgoimporter"
	"go/internal/gcimporter"
	"go/internal/srcimporter"
	"go/token"
	"go/types"
	"io"
	"runtime"
)

// Lookup函数返回一个读卡器来访问其包数据
// 给定的导入路径，如果找不到匹配的包，则为错误。
type Lookup func(path string) (io.ReadCloser, error)

// ForCompiler返回导入程序，以便从已安装的软件包导入
// 对于编译器“gc”和“gccgo”，或直接导入
// 如果编译器参数为“source”，则从源代码开始。在这个
// 在后一种情况下，在下列情况下进口可能失败：
// 导出的API不完全在纯Go源代码中定义
// （如果包API依赖于cgo定义的实体，则类型
// 检查者将无法访问这些内容）。
// None
// 每次生成的导入程序需要时都会调用查找函数
// 解析导入路径。在此模式下，导入器只能为
// 使用规范导入路径（不是相对或绝对路径）调用；
// 假定正在执行到规范导入路径的转换
// 由进口商的客户完成。
// None
// 必须提供查找功能以实现正确的模块感知操作。
// 不推荐：如果查找为零，为了向后兼容，导入程序
// 将尝试解析$GOPATH工作区中的导入。
func ForCompiler(fset *token.FileSet, compiler string, lookup Lookup) types.Importer {
	switch compiler {
	case "gc":
		return &gcimports{
			fset:     fset,
			packages: make(map[string]*types.Package),
			lookup:   lookup,
		}

	case "gccgo":
		var inst gccgoimporter.GccgoInstallation
		if err := inst.InitFromDriver("gccgo"); err != nil {
			return nil
		}
		return &gccgoimports{
			packages: make(map[string]*types.Package),
			importer: inst.GetImporter(nil, nil),
			lookup:   lookup,
		}

	case "source":
		if lookup != nil {
			panic("source importer for custom import path lookup not supported (issue #13847).")
		}

		return srcimporter.New(&build.Default, fset, make(map[string]*types.Package))
	}

	// 不支持编译器
	return nil
}

// 用于使用新文件集调用编译器。
// None
// 不推荐：使用ForCompiler，它填充文件集
// 使用导入器创建的对象的位置。
func For(compiler string, lookup Lookup) types.Importer {
	return ForCompiler(token.NewFileSet(), compiler, lookup)
}

// 默认值返回生成运行二进制文件的编译器的导入程序。
// 如果可用，结果将实现types.ImporterFrom。
func Default() types.Importer {
	return For(runtime.Compiler, nil)
}

// gc进口商

type gcimports struct {
	fset     *token.FileSet
	packages map[string]*types.Package
	lookup   Lookup
}

func (m *gcimports) Import(path string) (*types.Package, error) {
	return m.ImportFrom(path, "" /* no vendoring */, 0)
}

func (m *gcimports) ImportFrom(path, srcDir string, mode types.ImportMode) (*types.Package, error) {
	if mode != 0 {
		panic("mode must be 0")
	}
	return gcimporter.Import(m.fset, m.packages, path, srcDir, m.lookup)
}

// gccgo进口商

type gccgoimports struct {
	packages map[string]*types.Package
	importer gccgoimporter.Importer
	lookup   Lookup
}

func (m *gccgoimports) Import(path string) (*types.Package, error) {
	return m.ImportFrom(path, "" /* no vendoring */, 0)
}

func (m *gccgoimports) ImportFrom(path, srcDir string, mode types.ImportMode) (*types.Package, error) {
	if mode != 0 {
		panic("mode must be 0")
	}
	return m.importer(m.packages, path, srcDir, m.lookup)
}
